<?php

namespace App\Http\Controllers\Roulette;

use App\Contracts\Repositories\PrizeRepository as PrizeRepositoryContracts;
use App\Contracts\Services\Storage\StorageService;
use App\Entities\ActivityPrize;
use App\Entities\PrizeRecord;
use App\Events\PrizeBinded;
use App\Morefun\Prize\Flow;
use App\Morefun\Prize\PrizeService;
use Illuminate\Container\Container;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Ramsey\Uuid\Uuid;

class WebApiController
{
    protected $prizes;
    protected $prize;

    public function __construct(PrizeRepositoryContracts $prizes, PrizeService $prize)
    {
        $this->prizes = $prizes;
        $this->prize = $prize;
    }

    public function bindPrize(Request $request, $activityId, Flow $flow)
    {
        $input = $request->json()->all();
        Arr::set($input, 'activity_id', $activityId);
        $factory = Container::getInstance()->make('validator');
        $validator = $factory->make($input, [
            'activity_id' => 'required|uuid|exists:activities,id',
            'prize_id' => 'required|uuid|exists:prizes,id',
            'alias_name' => 'string|max:255',
            'winning_limit' => 'integer',
            'stock_limit' => 'numeric',
            'winning_probability' => 'numeric|between:0,1',
        ]);

        if ($validator->fails()) {
            return response()->failed(Arr::first($validator->errors()->all()));
        }

        if (!isset($input['surplus'])) {
            Arr::set($input, 'surplus', Arr::get($input, 'stock_limit', 0));
        }

        Arr::set($input, 'max_amount', 0);

        $binder = new ActivityPrize();
        $binder->fill($input);

        $database = Container::getInstance()->make('db');

        $id = $database->transaction(function () use ($binder, $flow, $activityId) {
            $binder->save();
            // 记录流水
            $flow->witch($binder->getAttribute('prize_id'))
                ->record(
                    PrizeRecord::DELIVERY,
                    $binder->getAttribute('stock_limit'),
                    $activityId
                );

            return $binder->getAttribute('id');
        });

        if ($id) {
            event(new PrizeBinded($activityId));
            return response()->success(compact('id'));
        }

        return response()->failed('创建失败');
    }

    public function updateBoundPrize(Request $request, $activityId, $id)
    {
        $input = $request->json()->all();
        Arr::set($input, 'activity_id', $activityId);
        $factory = Container::getInstance()->make('validator');
        $validator = $factory->make($input, [
            'activity_id' => 'required|uuid|exists:activities,id',
            'prize_id' => 'required|uuid|exists:prizes,id',
            'alias_name' => 'string|max:255',
            'winning_limit' => 'nullable|integer',
            'stock_limit' => 'numeric',
            'winning_probability' => 'numeric|between:0,1',
        ]);

        if ($validator->fails()) {
            return response()->failed(Arr::first($validator->errors()->all()));
        }

        if (!isset($input['surplus'])) {
            Arr::set($input, 'surplus', Arr::get($input, 'stock_limit', 0));
        }

        Arr::set($input, 'max_amount', 0);

        $binder = ActivityPrize::query()
            ->where('activity_id', $activityId)
            ->where('prize_id', $id)
            ->first();

        if (null === $binder) {
            return response()->failed('没有找到资源');
        }

        $binder->guard(['is_recycle']);
        $binder->fill($input);

        if ($binder->save()) {
            event(new PrizeBinded($activityId));
            return response()->success();
        }

        return response()->failed('修改失败');
    }

    public function unbindPrize($activityId, $id)
    {
        if (!Uuid::isValid($activityId) || !Uuid::isValid($id)) {
            return response()->failed('不是合法的activity_id/id');
        }

        $database = Container::getInstance()->make('db');

        $success = $database->transaction(function () use ($activityId, $id) {
            $binder = new ActivityPrize();
            $prize = $binder->where('activity_id', $activityId)
                ->where('prize_id', $id)
                ->first();

            if (null === $prize) {
                return false;
            }

            $prize->setAttribute('is_recycle', 1);

            return $prize->save() && (new Flow())->witch($id)
                ->record(PrizeRecord::RECYCLE, $prize->getAttribute('surplus'));
        });

        if ($success) {
            event(new PrizeBinded($activityId));
            return response()->success('奖品解绑成功');
        }

        return response()->failed('奖品解绑失败');
    }

    public function batchBindPrizes(Request $request, $activityId)
    {
        if (!Uuid::isValid($activityId)) {
            return response()->failed('活动id不合法');
        }

        $factory = Container::getInstance()->make('validator');
        $validator = $factory->make($request->json()->all(), [
            'prizes' => 'required|array',
        ]);

        if ($validator->fails()) {
            return response()->failed(Arr::first($validator->errors()->all()));
        }

        $prizes = $this->prize->formatMultiple($activityId, $request->json('prizes'));

        if (ActivityPrize::query()->insert($prizes)) {
            event(new PrizeBinded($activityId));
            return response()->success();
        }

        return response()->failed('创建失败');
    }

    public function getBoundPrizes(Request $request, $activityId)
    {
        if (!Uuid::isValid($activityId)) {
            return response()->failed('没找到资源');
        }

        $perPage = $request->get('per_page', 15) + 0;

        $prizes = ActivityPrize::with(['prize' => function ($query) {
            return $query->select([
                'id',
                'name',
                'expired_start',
                'expired_end',
                'stock_number',
                'background_image'
            ], 'prize.records');
        }])->where('activity_id', $activityId)
            ->where('is_recycle', 0)
            ->paginate($perPage);

        $this->prize->fillAvailableNumberForBindings($prizes);

        return response()->success($prizes);
    }
}
